package top.codedance.iotp.server.net;

import cd.io.netty.buffer.PooledByteBufAllocator;
import top.codedance.iotp.common.util.SystemUtil;
import top.codedance.iotp.server.ServerApplication;
import top.codedance.iotp.server.net.handle.listenner.TcpConnectionListener;
import top.codedance.iotp.server.net.handle.util.AsyncRequestService;
import top.codedance.iotp.server.net.handle.util.AsyncRequestServiceImpl;
import top.codedance.iotp.server.net.handle.util.SyncRequestService;
import top.codedance.iotp.server.net.handle.util.SyncRequestServiceImpl;
import top.codedance.iotp.server.net.initializer.TcpChannelInitializer;
import top.codedance.iotp.server.net.session.SessionManager;
import cd.io.netty.bootstrap.ServerBootstrap;
import cd.io.netty.channel.*;
import cd.io.netty.channel.nio.NioEventLoopGroup;
import cd.io.netty.channel.socket.nio.NioServerSocketChannel;
import cd.io.netty.handler.logging.LogLevel;
import cd.io.netty.handler.logging.LoggingHandler;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import java.util.Arrays;

public class TcpServer implements Server {
    private static Logger logger = ServerApplication.getLogger(TcpServer.class);

    public static final SyncRequestService syncRequestService = new SyncRequestServiceImpl(); //同步请求服务
    public static final AsyncRequestService asyncRequestService = new AsyncRequestServiceImpl(); //异步请求服务
    public static final SessionManager sessionManager = new SessionManager(); //session管理器
    public static long syncWaitTime = ServerApplication.commandCli.getArg("syncWaitTime", 15l); //同步执行等待的时间
    private int port = 10011;
    private String ip = "0.0.0.0";

    public TcpServer(String ip, int port){
        this.ip = ip;
        this.port = port;
    }

    public void run() {
        logger.setLevel(Level.toLevel(ServerApplication.commandCli.getArg("logLevel", "ERROR")));
        EventLoopGroup boss = new NioEventLoopGroup(ServerApplication.ioThreads);
        EventLoopGroup tcpWorker = new NioEventLoopGroup(ServerApplication.workerThreads);
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            ServerBootstrap group = bootstrap.group(boss, tcpWorker);
            String logLevelArg = ServerApplication.commandCli.getArg("logLevel", "OFF");
            if(Arrays.asList(LogLevel.values(), String.class).contains(logLevelArg)) {
                group.handler(new LoggingHandler(LogLevel.valueOf(logLevelArg)));
            }
            group.channel(NioServerSocketChannel.class) // 设置ChannelType
                    .option(ChannelOption.SO_BACKLOG, 512)
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.SO_RCVBUF, 128 * 1024)
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)
                    .childHandler(new TcpChannelInitializer());

            ChannelFuture channelFuture;
            if(!ServerApplication.enableIpBindPort || "0.0.0.0".equals(ip)){
                channelFuture = bootstrap.bind(port).sync();
            }else{
                channelFuture = bootstrap.bind(ip, port).sync();
            }

            if (channelFuture.isDone()) {
                SystemUtil.genTempFile(ServerApplication.TMP_FILE_NAME, String.valueOf(port));
                ServerApplication.syslogInfo(String.format("Tcp server bind port %s success", port));
            }
            channelFuture.addListener(new TcpConnectionListener());
            /**CloseFuture异步方式关闭*/
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            logger.debug(e.getMessage());
        } finally {
            boss.shutdownGracefully();
            tcpWorker.shutdownGracefully();
        }
    }
}
